<template>
  <div>
    
  </div>
</template>

<script>

import md from '@/markdowns/jsBase-async.md'

export default {
  name: 'jsBase-async',
  components: {
    
  },
  data () {
    return {
      
    }
  },
  watch: {
    
  },
  computed: {
    
  },
  methods: {
    
  },
  created () {
    
  },
  mounted () {
    this.$el.innerHTML = this.$md(md)
    
    // 下面有各种Promise处理代码
    /*let a = new MyPromise((resolve, reject) => {
      resolve(1)
    })
    
    a.then((res) => {
      console.log('then: ' + res)
      return MyPromise.reject(2)
    }).then((res) => {
      console.log('then: ' + res)
      return 3
    }).finally((res) => {
      console.log('finally: ' + res)
      return 100
    }).catch((e) => {
      console.log('catch: ' + e)
      return 4
    }).then((res) => {
      console.log('then: ' + res)
      return MyPromise.reject(5)
    }).catch((e) => {
      console.log('catch: ' + e)
    }).then((res) => {
      console.log('then: ' + res)
      return 6
    }).finally((res) => {
      console.log('finally: ' + res)
      return MyPromise.resolve(7)
    }).then((res) => {
      console.log('then: ' + res)
    })*/
    
    /*let a = () => {
      return new MyPromise((resolve, reject) => {
        setTimeout(() => {
          console.log('a 500')
          resolve('resolve a 500')
        }, 500)
      })
    }
    
    let b = () => {
      return new MyPromise((resolve, reject) => {
        setTimeout(() => {
          console.log('b 300')
          resolve('resolve b 300')
        }, 300)
      })
    }
    
    let c = () => {
      return new MyPromise((resolve, reject) => {
        setTimeout(() => {
          console.log('c 800')
          resolve('resolve c 800')
        }, 800)
      })
    }
    
    a().then((res) => {
      console.log(res)
      return b()
    }).then((res) => {
      console.log(res)
      return c()
    }).then((res) => {
      console.log(res)
    }).then((res) => {
      console.log(res)
    }).catch((e) => {
      console.log(e)
    }).finally(() => {
      console.log('finally')
    })*/
    
    /*new Promise((resolve, reject) => {
      console.log(0)
      resolve(1)
    }).then((res) => {
      console.log(res)
      new Promise((resolve, reject) => {
        console.log(10)
        resolve(11)
      }).then((res) => {
        console.log(res)
        return 12
      }).then((res) => {
        console.log(res)
      })
    }).then((res) => {
      console.log(2)
    })*/
  },
}

// 手写Promise
const STATE = {
  PENDING: 'pending',
  RESOLVED: 'resolved',
  REJECTED: 'rejected'
}

class MyPromise {
  constructor (callback = (resolve, reject) => {}) {
    // this.id = Math.random().toString(36).substr(2)
    // console.log('create', this.id)
    // 一旦状态变为resolved或者rejected后，不可改变
    this.state = STATE.PENDING
    // Promise成功的值 / Promise失败的原因
    this.result = undefined
    // this.resolvedAction 异步then回调函数
    // this.rejectedAction 异步catch回调函数
    // this.finallyAction 异步finally回调函数
    
    // 成功回调函数
    const resolve = (res) => {
      if (res instanceof MyPromise) {
        // 如果resolve一个Promise对象，要及时通过then展开
        res.then(resolve, reject)
        return
      }
      if (this.state === STATE.PENDING) {
        this.state = STATE.RESOLVED
        this.result = res
        if (this.resolvedAction) {
          // 执行then方法中保存的回调方法，用于应对异步场景
          this.resolvedAction(res)
        }
        if (this.finallyAction) {
          this.finallyAction()
        }
      }
    }
    const reject = (e) => {
      if (e instanceof MyPromise) {
        // 如果reject一个Promise对象，要及时通过then展开
        e.then(resolve, reject)
        return
      }
      if (this.state === STATE.PENDING) {
        this.state = STATE.REJECTED
        this.result = e
        if (this.rejectedAction) {
          this.rejectedAction(e)
        }
        if (this.finallyAction) {
          this.finallyAction()
        }
      }
    }
    
    // 如果回调函数执行出现问题，直接走reject
    try {
      callback(resolve, reject)
    }
    catch (e) {
      reject(e)
    }
  }
  
  then (onResolved = (res) => {}, onRejected = null) {
    if (this.state === STATE.RESOLVED) {
      if (typeof onResolved !== 'function') {
        // 状态为resolved时，但是then却不指定回调函数，直接忽略
        return this
      }
      const val = onResolved(this.result)
      return this._resolveCallbackReturn(val)    
    }
    if (this.state === STATE.REJECTED) {
      if (typeof onRejected !== 'function') {
        // 没指定错误回调函数，直接忽略
        return this
      }
      const val = onRejected(this.result)
      return this._resolveCallbackReturn(val)   
    }
    if (this.state === STATE.PENDING) {
      // 异步情况下，新建一个Promise，将当前then的异步也传递给下一个then
      return new MyPromise((resolve, reject) => {
        if (typeof onResolved === 'function') {
          this.resolvedAction = (res) => {
            let val = onResolved(res)
            val = this._resolveCallbackReturn(val, false)
            // console.log(this.id,this.state, res, val)
            resolve(val)
          }          
        }
        else {
          // 当用户不传onResolved函数，为了避免链式调用中断，还是要建立桥梁，只是不再执行回调函数了
          this.resolvedAction = (res) => {
            resolve(res)
          }     
        }
        if (typeof onRejected === 'function') {
          this.rejectedAction = (e) => {
            let val = onRejected(e)
            val = this._resolveCallbackReturn(val, false)
            reject(val)
          }          
        }
        else {
          // 当用户不传onRejected函数，为了避免链式调用中断，还是要建立桥梁，只是不再执行回调函数了
          this.rejectedAction = (e) => {
            reject(e)
          }
        }
      })
    }    
  }
  
  // 本质上就是then的语法糖
  catch (callback = (e) => {}) {
    return this.then(null, callback)
  }
  
  // 只是简单地执行回调函数而已
  finally (callback = () => {}) {
    if (this.state === STATE.PENDING) {
      // 异步情况下，要维持住链子
      if (typeof callback === 'function') {
        this.finallyAction = () => {
          callback()
        }
      }
    }
    else {
      // resolved和rejected状态下立即执行
      if (typeof callback === 'function') {
        callback()
      }      
    }
    return this
  }
  
  // 处理返回值，isParse代表是否封装非promise对象
  _resolveCallbackReturn (val, isParse = true) {
    if (val instanceof MyPromise) {
      // 返回的是Promise
      if (this === val) {
        // Promise回调中不允许返回本身
        return MyPromise.reject(new TypeError('Chaining cycle detected for promise'))
      }
      // 如果是Promise对象，则原路返回
      return val
    }
    if (isParse) {
      // 其余类型的对象，封装成Promise<resolved>返回
      return new MyPromise((resolve, reject) => {
        resolve(val)
      })        
    }
    return val
  }
  
  static resolve (val) {
    return new MyPromise((resolve, reject) => {
      resolve(val)
    })
  }
  
  static reject (e) {
    return new MyPromise((resolve, reject) => {
      reject(e)
    })
  }
  
  static all (arr = []) {
    return new MyPromise((resolve, reject) => {
      let result = []
      let count = 0
      const len = arr.length
      for (let i = 0; i < len; i++) {
        arr[i].then((res) => {
          result.push(data)
          count++
          if (count === len) {
            resolve(result)
          }
        })
        .catch((e) => {
          reject(e)
        })
      }
    })
  }
  
  static race (arr = []) {
    return new MyPromise((resolve, reject) => {
      const len = arr.length
      for (let i = 0; i < len; i++) {
        arr[i].then((res) => {
          resolve(res)
        })
        .catch((e) => {
          reject(e)
        })
      }
    })
  }
}
  
</script>

<style>
</style>
